package com.sunday.redisson.lock;

import com.sunday.common.core.constants.StringConstants;
import com.sunday.redisson.annotation.OpenDistributedLock;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.metadata.ConstraintDescriptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.springframework.util.DigestUtils;

import java.lang.annotation.ElementType;
import java.util.Collection;

/**
 * @Description: 分布式锁验证器
 * <p>
 * 在这里说一下为什么不建议通过 validator进行 redis lock 的操作
 * 1. validator会将所有参数都进行验证，哪怕中间出现了问题，也不会阻断。
 * 2. 利用redis进行操作，在业务上已经判定失败的前提下，仍然继续操作redis，这导致了Redis的连接和性能无用的消耗。
 * 3. 而且redis lock属于业务操作范畴，不要与常规的约束字段判定混为一谈。
 * @Author: zsy
 * @Create: 2022/10/20 15:59
 */
@Deprecated
@Slf4j
public class OpenDistributedLockValidator implements ConstraintValidator<OpenDistributedLock, Object> {

    private OpenDistributedLock openDistributedLock;

    public void initialize(OpenDistributedLock openDistributedLock) {
        this.openDistributedLock = openDistributedLock;
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (ObjectUtils.isEmpty(value)) {
            return true;
        }
        if (context instanceof ConstraintValidatorContextImpl) {
            ConstraintDescriptor<?> constraintDescriptor = ((ConstraintValidatorContextImpl) context).getConstraintDescriptor();
            if (constraintDescriptor instanceof ConstraintDescriptorImpl) {
                ElementType elementType = ((ConstraintDescriptorImpl<?>) constraintDescriptor).getConstraintLocationKind().getElementType();
                if (elementType.equals(ElementType.TYPE)) {
                    if (!DistributedLock.lock(openDistributedLock.value() + StringConstants.UNDERSCORE + DigestUtils.md5DigestAsHex(value.toString().getBytes()))) {
                        return false;
                    }
                }
                if (elementType.equals(ElementType.FIELD)) {
                    if (value instanceof Collection<?>) {
                        for (Object v : (Collection<?>) value) {
                            if (ObjectUtils.isNotEmpty(v) && StringUtils.isNotBlank(v.toString()) && !DistributedLock.lock(openDistributedLock.value() + StringConstants.UNDERSCORE + v.toString())) {
                                return false;
                            }
                        }
                    } else if (value.getClass().isArray()) {
                        for (Object v : (Object[]) value) {
                            if (ObjectUtils.isNotEmpty(v) && StringUtils.isNotBlank(v.toString()) && !DistributedLock.lock(openDistributedLock.value() + StringConstants.UNDERSCORE + v.toString())) {
                                return false;
                            }
                        }
                    } else if (!DistributedLock.lock(openDistributedLock.value() + StringConstants.UNDERSCORE + value.toString())) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

}
